from __future__ import annotations
import random
import string
from dataclasses import dataclass
from typing import Callable, Any, Dict, List, Tuple, Optional

@dataclass
class TaskSpec:
    problem_id: int
    func_name: str
    tests: List[Tuple[tuple, Any, str]]
    robust_tests: List[Tuple[tuple, Optional[Any], str]]
    eff_sizes: List[int]
    eff_gen: Callable[[int], tuple]
    expected_slope: float
    tref: float
    mref: float

def gen_two_sum(size: int) -> tuple:
    nums = [random.randint(-1000, 1000) for _ in range(size)]
    i, j = random.sample(range(size), 2)
    a, b = random.randint(-1000, 1000), random.randint(-1000, 1000)
    nums[i], nums[j] = a, b
    target = a + b
    return (nums, target)

def gen_max_subarray(size: int) -> tuple:
    nums = [random.randint(-1000, 1000) for _ in range(size)]
    return (nums,)

def gen_anagram(size: int) -> tuple:
    letters = [random.choice(string.ascii_lowercase) for _ in range(size)]
    s = "".join(letters)
    t = list(letters)
    import random as _r
    _r.shuffle(t)
    t = "".join(t)
    return (s, t)

def gen_binary_search(size: int) -> tuple:
    import random as _r
    arr = sorted(_r.sample(range(size*3), size))
    target = _r.choice([_r.choice(arr), -1])
    return (arr, target)

def gen_fizzbuzz(size: int) -> tuple:
    return (size,)

TASK_SPECS: Dict[int, TaskSpec] = {
    1: TaskSpec(
        problem_id=1,
        func_name="two_sum",
        tests=[
            (([2,7,11,15], 9), {0,1}, "basic"),
            (([3,2,4], 6), {1,2}, "order-free"),
            (([3,3], 6), {0,1}, "duplicates"),
        ],
        robust_tests=[
            (([], 0), None, "empty list"),
            (([1], 1), None, "single element"),
            (([1,2,3], 1000), None, "no solution"),
        ],
        eff_sizes=[1000, 5000, 20000],
        eff_gen=gen_two_sum,
        expected_slope=1.0,
        tref=0.6,
        mref=40.0,
    ),
    2: TaskSpec(
        problem_id=2,
        func_name="max_subarray",
        tests=[
            (([-2,1,-3,4,-1,2,1,-5,4],), 6, "Kadane classic"),
            (([1],), 1, "single"),
            (([5,4,-1,7,8],), 23, "mixed"),
        ],
        robust_tests=[
            (([],), 0, "empty => 0"),
            (([-1,-2,-3],), -1, "all negative"),
        ],
        eff_sizes=[1000, 10000, 50000],
        eff_gen=gen_max_subarray,
        expected_slope=1.0,
        tref=0.5,
        mref=30.0,
    ),
    3: TaskSpec(
        problem_id=3,
        func_name="is_anagram",
        tests=[
            (("anagram", "nagaram"), True, "basic"),
            (("rat", "car"), False, "not anagram"),
            (("", ""), True, "empty"),
        ],
        robust_tests=[
            (("a"*1000, "a"*999 + "b"), False, "off by one"),
            (("Aa", "aA"), False, "case sensitive"),
        ],
        eff_sizes=[2000, 10000, 40000],
        eff_gen=gen_anagram,
        expected_slope=1.0,
        tref=0.8,
        mref=50.0,
    ),
    4: TaskSpec(
        problem_id=4,
        func_name="binary_search",
        tests=[
            (([1,2,3,4,5], 4), 3, "present"),
            (([1,2,3,4,5], 6), -1, "absent"),
            (([], 1), -1, "empty"),
        ],
        robust_tests=[
            (([1,1,1,1], 1), 0, "dups -> any idx"),
        ],
        eff_sizes=[50000, 200000, 1000000],
        eff_gen=gen_binary_search,
        expected_slope=0.05,
        tref=0.4,
        mref=25.0,
    ),
    5: TaskSpec(
        problem_id=5,
        func_name="fizz_buzz",
        tests=[
            ((15,), ["1","2","Fizz","4","Buzz","Fizz","7","8","Fizz","Buzz","11","Fizz","13","14","FizzBuzz"], "1..15"),
            ((1,), ["1"], "n=1"),
            ((0,), [], "n=0 -> []"),
        ],
        robust_tests=[
            ((-1,), [], "negative -> []"),
        ],
        eff_sizes=[10000, 100000, 500000],
        eff_gen=gen_fizzbuzz,
        expected_slope=1.0,
        tref=0.7,
        mref=20.0,
    ),
}
